﻿using NUnit.Framework;

namespace JH
{
    public class TestInterfaceEaseFunction
    {
        /// <summary>
        /// 创建一个测试用结构体实现ITweenData接口
        /// </summary>
        private struct TestVector2 : ITweenData<TestVector2>
        {
            public readonly float X;
            public readonly float Y;

            public TestVector2(float x, float y)
            {
                this.X = x;
                this.Y = y;
            }

            public TestVector2 Tween(TestVector2 start, TestVector2 end, Ease ease, float f)
            {
                return new TestVector2(
                    EaseFunctionNumeric.Tween(start.X, end.X, ease, f),
                    EaseFunctionNumeric.Tween(start.Y, end.Y, ease, f)
                );
            }
        }

        [Test]
        public void TestITweenDataImplementation()
        {
            // Arrange
            TestVector2 start = new TestVector2(0, 0);
            TestVector2 end = new TestVector2(100, 200);
            float progress = 0.5f;

            // Act
            TestVector2 result = EaseFunctionNumeric.Tween(start, end, Ease.Linear, progress);

            // Assert
            Assert.AreEqual(50, result.X, "X值在线性插值0.5时应该是50");
            Assert.AreEqual(100, result.Y, "Y值在线性插值0.5时应该是100");
        }

        [Test]
        public void TestMultipleEaseTypes()
        {
            // Arrange
            TestVector2 start = new TestVector2(0, 0);
            TestVector2 end = new TestVector2(100, 100);
            float progress = 0.5f;

            // Act & Assert
            // 测试不同缓动类型
            var linearResult = EaseFunctionNumeric.Tween(start, end, Ease.Linear, progress);
            var easeInResult = EaseFunctionNumeric.Tween(start, end, Ease.InQuad, progress);

            Assert.AreNotEqual(linearResult.X, easeInResult.X, "线性和二次缓入的结果应该不同");
        }

        [Test]
        public void TestBoundaryConditions()
        {
            // Arrange
            TestVector2 start = new TestVector2(0, 0);
            TestVector2 end = new TestVector2(100, 100);

            // Act & Assert
            // 测试起始点
            var startResult = EaseFunctionNumeric.Tween(start, end, Ease.Linear, 0f);
            Assert.AreEqual(0, startResult.X, "起始点x应该是0");
            Assert.AreEqual(0, startResult.Y, "起始点y应该是0");

            // 测试终点
            var endResult = EaseFunctionNumeric.Tween(start, end, Ease.Linear, 1f);
            Assert.AreEqual(100, endResult.X, "终点x应该是100");
            Assert.AreEqual(100, endResult.Y, "终点y应该是100");
        }

        [Test]
        public void TestNegativeValues()
        {
            // Arrange
            TestVector2 start = new TestVector2(-100, -200);
            TestVector2 end = new TestVector2(100, 200);
            float progress = 0.5f;

            // Act
            var result = EaseFunctionNumeric.Tween(start, end, Ease.Linear, progress);

            // Assert
            Assert.AreEqual(0, result.X, "负值到正值的中间点x应该是0");
            Assert.AreEqual(0, result.Y, "负值到正值的中间点y应该是0");
        }

        [Test]
        public void TestInvalidProgress()
        {
            // Arrange
            TestVector2 start = new TestVector2(0, 0);
            TestVector2 end = new TestVector2(100, 100);

            // Act & Assert
            // 测试超出范围的进度值
            Assert.Throws<System.ArgumentOutOfRangeException>(
                () => { EaseFunctionNumeric.Tween(start, end, Ease.Linear, -0.1f); }, "进度值小于0应该抛出异常");

            Assert.Throws<System.ArgumentOutOfRangeException>(
                () => { EaseFunctionNumeric.Tween(start, end, Ease.Linear, 1.1f); }, "进度值大于1应该抛出异常");
        }

        [Test]
        public void TestNullHandling()
        {
            // 如果你的实现允许null值，你应该测试null的处理
            TestVector2? nullStart = null;
            TestVector2 end = new TestVector2(100, 100);

            // ReSharper disable once ExpressionIsAlwaysNull
            Assert.Throws<System.ArgumentNullException>(
                () => { EaseFunctionNumeric.Tween(nullStart, end, Ease.Linear, 0.5f); },
                "null值应该抛出ArgumentNullException");
        }
    }
}